/**
* Copyright (c) By zengqh.
*
* This program is just for fun or demo, in the hope that it  
* will be useful, you can redistribute it and/or modify freely.
*
* Time: 2013/03/03
* File: IndexBuffer.cpp
* Blog: http://www.cnblogs.com/zengqh/
**/

#include "OGLIndexBuffer.h"

namespace HY
{
OGLIndexBuffer::~OGLIndexBuffer()
{
	release();
}

uint32 OGLIndexBuffer::getHandle() const
{
	return handle_;
}

OGLIndexBuffer::OGLIndexBuffer()
: IndexBuffer(UShort)
, handle_(0)
, lock_data_(0)
, usage_api_(0)
{

}

bool OGLIndexBuffer::create(uint32 elems, uint32 usage, uint32 type)
{
	uint32 nElementSizeAPI;
	elem_type_ = type;

	if (elem_type_ == UInt)
	{
		nElementSizeAPI = sizeof(uint32);
	}
	else if (elem_type_ == UShort)
	{
		nElementSizeAPI = sizeof(uint16);
	}
	else
	{
		HY_ASSERT(0);
		return false;
	}

	// Get API dependent usage
	if (usage_ == BufferUsage::Static)
	{
		usage_api_ = GL_STATIC_DRAW;
	}
	else if (usage_ == BufferUsage::Dynamic)
	{
		usage_api_ = GL_DYNAMIC_DRAW;
	}
	else if (usage_ == BufferUsage::WriteOnly)
	{
		usage_api_ = GL_STREAM_DRAW;
	}
	else
	{
		HY_ASSERT(0);
		return false;
	}
	
	elems_ = elems;
	size_ = nElementSizeAPI * elems;
	usage_ = usage;

	glGenBuffers(1, &handle_);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, handle_);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, size_, 0, usage_api_);

	return true;
}

void OGLIndexBuffer::bind()
{
	HY_ASSERT(handle_);
	glBindBuffer(GL_ARRAY_BUFFER, handle_);
}

void OGLIndexBuffer::unbind()
{
	glBindBuffer(GL_ARRAY_BUFFER, 0);
}

void OGLIndexBuffer::release()
{
	if (!handle_)
	{
		return;
	}

	glDeleteBuffers(1, &handle_);
	handle_ = 0;

	elems_ = 0;
	size_ = 0;
	usage_ = 0;
	usage_api_ = 0;
}

void* OGLIndexBuffer::lock(uint32 flags)
{
	if (lock_data_)
	{
		return lock_data_;
	}

	if (!handle_)
	{
		HY_ASSERT(0);
		return 0;
	}

	uint32 nFlagAPI;
	if (flags == Lock::ReadOnly) 
	{
		nFlagAPI        = GL_READ_ONLY;
	} 
	else if (flags == Lock::WriteOnly) 
	{
		nFlagAPI        = GL_WRITE_ONLY;
	} 
	else if (flags == Lock::ReadWrite) 
	{
		nFlagAPI        = GL_READ_WRITE;
	} 
	else 
	{
		HY_ASSERT(0);
		return 0;
	}

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, handle_);
	lock_data_ = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, nFlagAPI);

	return lock_data_;
}

bool OGLIndexBuffer::unlock()
{
	if (!lock_data_)
	{
		HY_ASSERT(0);
		return false;
	}

	if (!handle_)
	{
		HY_ASSERT(0);
		return false;
	}

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, handle_);
	glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);

	lock_data_ = 0;

	return true;
}

}